<!doctype html>

<html>
<head>
  <link rel="shortcut icon" href="static/images/favicon.ico" type="image/x-icon">
  <title>table.js (Closure Library API Documentation - JavaScript)</title>
  <link rel="stylesheet" href="static/css/base.css">
  <link rel="stylesheet" href="static/css/doc.css">
  <link rel="stylesheet" href="static/css/sidetree.css">
  <link rel="stylesheet" href="static/css/prettify.css">

  <script>
     var _staticFilePath = "static/";
     var _typeTreeName = "goog";
     var _fileTreeName = "Source";
  </script>

  <script src="static/js/doc.js">
  </script>


  <meta charset="utf8">
</head>

<body onload="grokdoc.onLoad();">

<div id="header">
  <div class="g-section g-tpl-50-50 g-split">
    <div class="g-unit g-first">
      <a id="logo" href="index.html">Closure Library API Documentation</a>
    </div>

    <div class="g-unit">
      <div class="g-c">
        <strong>Go to class or file:</strong>
        <input type="text" id="ac">
      </div>
    </div>
  </div>
</div>

<div class="clear"></div>

<h2><a href="closure_goog_editor_table.js.html">table.js</a></h2>

<pre class="prettyprint lang-js">
<a name="line1"></a>// Copyright 2008 The Closure Library Authors. All Rights Reserved.
<a name="line2"></a>//
<a name="line3"></a>// Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);
<a name="line4"></a>// you may not use this file except in compliance with the License.
<a name="line5"></a>// You may obtain a copy of the License at
<a name="line6"></a>//
<a name="line7"></a>//      http://www.apache.org/licenses/LICENSE-2.0
<a name="line8"></a>//
<a name="line9"></a>// Unless required by applicable law or agreed to in writing, software
<a name="line10"></a>// distributed under the License is distributed on an &quot;AS-IS&quot; BASIS,
<a name="line11"></a>// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
<a name="line12"></a>// See the License for the specific language governing permissions and
<a name="line13"></a>// limitations under the License.
<a name="line14"></a>
<a name="line15"></a>/**
<a name="line16"></a> * @fileoverview Table editing support.
<a name="line17"></a> * This file provides the class goog.editor.Table and two
<a name="line18"></a> * supporting classes, goog.editor.TableRow and
<a name="line19"></a> * goog.editor.TableCell. Together these provide support for
<a name="line20"></a> * high level table modifications: Adding and deleting rows and columns,
<a name="line21"></a> * and merging and splitting cells.
<a name="line22"></a> *
<a name="line23"></a> * @supported IE6+, WebKit 525+, Firefox 2+.
<a name="line24"></a> */
<a name="line25"></a>
<a name="line26"></a>goog.provide(&#39;goog.editor.Table&#39;);
<a name="line27"></a>goog.provide(&#39;goog.editor.TableCell&#39;);
<a name="line28"></a>goog.provide(&#39;goog.editor.TableRow&#39;);
<a name="line29"></a>
<a name="line30"></a>goog.require(&#39;goog.debug.Logger&#39;);
<a name="line31"></a>goog.require(&#39;goog.dom&#39;);
<a name="line32"></a>goog.require(&#39;goog.dom.DomHelper&#39;);
<a name="line33"></a>goog.require(&#39;goog.dom.NodeType&#39;);
<a name="line34"></a>goog.require(&#39;goog.dom.TagName&#39;);
<a name="line35"></a>goog.require(&#39;goog.string.Unicode&#39;);
<a name="line36"></a>goog.require(&#39;goog.style&#39;);
<a name="line37"></a>
<a name="line38"></a>
<a name="line39"></a>
<a name="line40"></a>/**
<a name="line41"></a> * Class providing high level table editing functions.
<a name="line42"></a> * @param {Element} node Element that is a table or descendant of a table.
<a name="line43"></a> * @constructor
<a name="line44"></a> */
<a name="line45"></a>goog.editor.Table = function(node) {
<a name="line46"></a>  this.element = goog.dom.getAncestorByTagNameAndClass(node,
<a name="line47"></a>      goog.dom.TagName.TABLE);
<a name="line48"></a>  if (!this.element) {
<a name="line49"></a>    this.logger_.severe(
<a name="line50"></a>        &quot;Can&#39;t create Table based on a node &quot; +
<a name="line51"></a>        &quot;that isn&#39;t a table, or descended from a table.&quot;);
<a name="line52"></a>  }
<a name="line53"></a>  this.dom_ = goog.dom.getDomHelper(this.element);
<a name="line54"></a>  this.refresh();
<a name="line55"></a>};
<a name="line56"></a>
<a name="line57"></a>
<a name="line58"></a>/**
<a name="line59"></a> * Logger object for debugging and error messages.
<a name="line60"></a> * @type {goog.debug.Logger}
<a name="line61"></a> * @private
<a name="line62"></a> */
<a name="line63"></a>goog.editor.Table.prototype.logger_ =
<a name="line64"></a>    goog.debug.Logger.getLogger(&#39;goog.editor.Table&#39;);
<a name="line65"></a>
<a name="line66"></a>
<a name="line67"></a>/**
<a name="line68"></a> * Walks the dom structure of this object&#39;s table element and populates
<a name="line69"></a> * this.rows with goog.editor.TableRow objects. This is done initially
<a name="line70"></a> * to populate the internal data structures, and also after each time the
<a name="line71"></a> * DOM structure is modified. Currently this means that the all existing
<a name="line72"></a> * information is discarded and re-read from the DOM.
<a name="line73"></a> */
<a name="line74"></a>// TODO(user): support partial refresh to save cost of full update
<a name="line75"></a>// every time there is a change to the DOM.
<a name="line76"></a>goog.editor.Table.prototype.refresh = function() {
<a name="line77"></a>  var rows = this.rows = [];
<a name="line78"></a>  var tbody = this.element.getElementsByTagName(goog.dom.TagName.TBODY)[0];
<a name="line79"></a>  if (!tbody) {
<a name="line80"></a>    return;
<a name="line81"></a>  }
<a name="line82"></a>  var trs = [];
<a name="line83"></a>  for (var child = tbody.firstChild; child; child = child.nextSibling) {
<a name="line84"></a>    if (child.nodeName == goog.dom.TagName.TR) {
<a name="line85"></a>      trs.push(child);
<a name="line86"></a>    }
<a name="line87"></a>  }
<a name="line88"></a>
<a name="line89"></a>  for (var rowNum = 0, tr; tr = trs[rowNum]; rowNum++) {
<a name="line90"></a>    var existingRow = rows[rowNum];
<a name="line91"></a>    var tds = goog.editor.Table.getChildCellElements(tr);
<a name="line92"></a>    var columnNum = 0;
<a name="line93"></a>    // A note on cellNum vs. columnNum: A cell is a td/th element. Cells may
<a name="line94"></a>    // use colspan/rowspan to extend over multiple rows/columns. cellNum
<a name="line95"></a>    // is the dom element number, columnNum is the logical column number.
<a name="line96"></a>    for (var cellNum = 0, td; td = tds[cellNum]; cellNum++) {
<a name="line97"></a>      // If there&#39;s already a cell extending into this column
<a name="line98"></a>      // (due to that cell&#39;s colspan/rowspan), increment the column counter.
<a name="line99"></a>      while (existingRow &amp;&amp; existingRow.columns[columnNum]) {
<a name="line100"></a>        columnNum++;
<a name="line101"></a>      }
<a name="line102"></a>      var cell = new goog.editor.TableCell(td, rowNum, columnNum);
<a name="line103"></a>      // Place this cell in every row and column into which it extends.
<a name="line104"></a>      for (var i = 0; i &lt; cell.rowSpan; i++) {
<a name="line105"></a>        var cellRowNum = rowNum + i;
<a name="line106"></a>        // Create TableRow objects in this.rows as needed.
<a name="line107"></a>        var cellRow = rows[cellRowNum];
<a name="line108"></a>        if (!cellRow) {
<a name="line109"></a>          // TODO(user): try to avoid second trs[] lookup.
<a name="line110"></a>          rows.push(
<a name="line111"></a>              cellRow = new goog.editor.TableRow(trs[cellRowNum], cellRowNum));
<a name="line112"></a>        }
<a name="line113"></a>        // Extend length of column array to make room for this cell.
<a name="line114"></a>        var minimumColumnLength = columnNum + cell.colSpan;
<a name="line115"></a>        if (cellRow.columns.length &lt; minimumColumnLength) {
<a name="line116"></a>          cellRow.columns.length = minimumColumnLength;
<a name="line117"></a>        }
<a name="line118"></a>        for (var j = 0; j &lt; cell.colSpan; j++) {
<a name="line119"></a>          var cellColumnNum = columnNum + j;
<a name="line120"></a>          cellRow.columns[cellColumnNum] = cell;
<a name="line121"></a>        }
<a name="line122"></a>      }
<a name="line123"></a>      columnNum += cell.colSpan;
<a name="line124"></a>    }
<a name="line125"></a>  }
<a name="line126"></a>};
<a name="line127"></a>
<a name="line128"></a>
<a name="line129"></a>/**
<a name="line130"></a> * Returns all child elements of a TR element that are of type TD or TH.
<a name="line131"></a> * @param {Element} tr TR element in which to find children.
<a name="line132"></a> * @return {Array.&lt;Element&gt;} array of child cell elements.
<a name="line133"></a> */
<a name="line134"></a>goog.editor.Table.getChildCellElements = function(tr) {
<a name="line135"></a>  var cells = [];
<a name="line136"></a>  for (var i = 0, cell; cell = tr.childNodes[i]; i++) {
<a name="line137"></a>    if (cell.nodeName == goog.dom.TagName.TD ||
<a name="line138"></a>        cell.nodeName == goog.dom.TagName.TH) {
<a name="line139"></a>      cells.push(cell);
<a name="line140"></a>    }
<a name="line141"></a>  }
<a name="line142"></a>  return cells;
<a name="line143"></a>};
<a name="line144"></a>
<a name="line145"></a>
<a name="line146"></a>/**
<a name="line147"></a> * Inserts a new row in the table. The row will be populated with new
<a name="line148"></a> * cells, and existing rowspanned cells that overlap the new row will
<a name="line149"></a> * be extended.
<a name="line150"></a> * @param {number=} opt_rowIndex Index at which to insert the row. If
<a name="line151"></a> *     this is omitted the row will be appended to the end of the table.
<a name="line152"></a> * @return {Element} The new row.
<a name="line153"></a> */
<a name="line154"></a>goog.editor.Table.prototype.insertRow = function(opt_rowIndex) {
<a name="line155"></a>  var rowIndex = goog.isDefAndNotNull(opt_rowIndex) ?
<a name="line156"></a>      opt_rowIndex : this.rows.length;
<a name="line157"></a>  var refRow;
<a name="line158"></a>  var insertAfter;
<a name="line159"></a>  if (rowIndex == 0) {
<a name="line160"></a>    refRow = this.rows[0];
<a name="line161"></a>    insertAfter = false;
<a name="line162"></a>  } else {
<a name="line163"></a>    refRow = this.rows[rowIndex - 1];
<a name="line164"></a>    insertAfter = true;
<a name="line165"></a>  }
<a name="line166"></a>  var newTr = this.dom_.createElement(&#39;tr&#39;);
<a name="line167"></a>  for (var i = 0, cell; cell = refRow.columns[i]; i += 1) {
<a name="line168"></a>    // Check whether the existing cell will span this new row.
<a name="line169"></a>    // If so, instead of creating a new cell, extend
<a name="line170"></a>    // the rowspan of the existing cell.
<a name="line171"></a>    if ((insertAfter &amp;&amp; cell.endRow &gt; rowIndex) ||
<a name="line172"></a>        (!insertAfter &amp;&amp; cell.startRow &lt; rowIndex)) {
<a name="line173"></a>      cell.setRowSpan(cell.rowSpan + 1);
<a name="line174"></a>      if (cell.colSpan &gt; 1) {
<a name="line175"></a>        i += cell.colSpan - 1;
<a name="line176"></a>      }
<a name="line177"></a>    } else {
<a name="line178"></a>      newTr.appendChild(this.createEmptyTd());
<a name="line179"></a>    }
<a name="line180"></a>    if (insertAfter) {
<a name="line181"></a>      goog.dom.insertSiblingAfter(newTr, refRow.element);
<a name="line182"></a>    } else {
<a name="line183"></a>      goog.dom.insertSiblingBefore(newTr, refRow.element);
<a name="line184"></a>    }
<a name="line185"></a>  }
<a name="line186"></a>  this.refresh();
<a name="line187"></a>  return newTr;
<a name="line188"></a>};
<a name="line189"></a>
<a name="line190"></a>
<a name="line191"></a>/**
<a name="line192"></a> * Inserts a new column in the table. The column will be created by
<a name="line193"></a> * inserting new TD elements in each row, or extending the colspan
<a name="line194"></a> * of existing TD elements.
<a name="line195"></a> * @param {number=} opt_colIndex Index at which to insert the column. If
<a name="line196"></a> *     this is omitted the column will be appended to the right side of
<a name="line197"></a> *     the table.
<a name="line198"></a> * @return {Array.&lt;Element&gt;} Array of new cell elements that were created
<a name="line199"></a> *     to populate the new column.
<a name="line200"></a> */
<a name="line201"></a>goog.editor.Table.prototype.insertColumn = function(opt_colIndex) {
<a name="line202"></a>  // TODO(user): set column widths in a way that makes sense.
<a name="line203"></a>  var colIndex = goog.isDefAndNotNull(opt_colIndex) ?
<a name="line204"></a>      opt_colIndex :
<a name="line205"></a>      (this.rows[0] &amp;&amp; this.rows[0].columns.length) || 0;
<a name="line206"></a>  var newTds = [];
<a name="line207"></a>  for (var rowNum = 0, row; row = this.rows[rowNum]; rowNum++) {
<a name="line208"></a>    var existingCell = row.columns[colIndex];
<a name="line209"></a>    if (existingCell &amp;&amp; existingCell.endCol &gt;= colIndex &amp;&amp;
<a name="line210"></a>        existingCell.startCol &lt; colIndex) {
<a name="line211"></a>      existingCell.setColSpan(existingCell.colSpan + 1);
<a name="line212"></a>      rowNum += existingCell.rowSpan - 1;
<a name="line213"></a>    } else {
<a name="line214"></a>      var newTd = this.createEmptyTd();
<a name="line215"></a>      // TODO(user): figure out a way to intelligently size new columns.
<a name="line216"></a>      newTd.style.width = goog.editor.Table.OPTIMUM_EMPTY_CELL_WIDTH + &#39;px&#39;;
<a name="line217"></a>      this.insertCellElement(newTd, rowNum, colIndex);
<a name="line218"></a>      newTds.push(newTd);
<a name="line219"></a>    }
<a name="line220"></a>  }
<a name="line221"></a>  this.refresh();
<a name="line222"></a>  return newTds;
<a name="line223"></a>};
<a name="line224"></a>
<a name="line225"></a>
<a name="line226"></a>/**
<a name="line227"></a> * Removes a row from the table, removing the TR element and
<a name="line228"></a> * decrementing the rowspan of any cells in other rows that overlap the row.
<a name="line229"></a> * @param {number} rowIndex Index of the row to delete.
<a name="line230"></a> */
<a name="line231"></a>goog.editor.Table.prototype.removeRow = function(rowIndex) {
<a name="line232"></a>  var row = this.rows[rowIndex];
<a name="line233"></a>  if (!row) {
<a name="line234"></a>    this.logger_.warning(
<a name="line235"></a>        &quot;Can&#39;t remove row at position &quot; + rowIndex + &#39;: no such row.&#39;);
<a name="line236"></a>  }
<a name="line237"></a>  for (var i = 0, cell; cell = row.columns[i]; i += cell.colSpan) {
<a name="line238"></a>    if (cell.rowSpan &gt; 1) {
<a name="line239"></a>      cell.setRowSpan(cell.rowSpan - 1);
<a name="line240"></a>      if (cell.startRow == rowIndex) {
<a name="line241"></a>        // Rowspanned cell started in this row - move it down to the next row.
<a name="line242"></a>        this.insertCellElement(cell.element, rowIndex + 1, cell.startCol);
<a name="line243"></a>      }
<a name="line244"></a>    }
<a name="line245"></a>  }
<a name="line246"></a>  row.element.parentNode.removeChild(row.element);
<a name="line247"></a>  this.refresh();
<a name="line248"></a>};
<a name="line249"></a>
<a name="line250"></a>
<a name="line251"></a>/**
<a name="line252"></a> * Removes a column from the table. This is done by removing cell elements,
<a name="line253"></a> * or shrinking the colspan of elements that span multiple columns.
<a name="line254"></a> * @param {number} colIndex Index of the column to delete.
<a name="line255"></a> */
<a name="line256"></a>goog.editor.Table.prototype.removeColumn = function(colIndex) {
<a name="line257"></a>  for (var i = 0, row; row = this.rows[i]; i++) {
<a name="line258"></a>    var cell = row.columns[colIndex];
<a name="line259"></a>    if (!cell) {
<a name="line260"></a>      this.logger_.severe(
<a name="line261"></a>          &quot;Can&#39;t remove cell at position &quot; + i + &#39;, &#39; + colIndex +
<a name="line262"></a>          &#39;: no such cell.&#39;);
<a name="line263"></a>    }
<a name="line264"></a>    if (cell.colSpan &gt; 1) {
<a name="line265"></a>      cell.setColSpan(cell.colSpan - 1);
<a name="line266"></a>    } else {
<a name="line267"></a>      cell.element.parentNode.removeChild(cell.element);
<a name="line268"></a>    }
<a name="line269"></a>    // Skip over following rows that contain this same cell.
<a name="line270"></a>    i += cell.rowSpan - 1;
<a name="line271"></a>  }
<a name="line272"></a>  this.refresh();
<a name="line273"></a>};
<a name="line274"></a>
<a name="line275"></a>
<a name="line276"></a>/**
<a name="line277"></a> * Merges multiple cells into a single cell, and sets the rowSpan and colSpan
<a name="line278"></a> * attributes of the cell to take up the same space as the original cells.
<a name="line279"></a> * @param {number} startRowIndex Top coordinate of the cells to merge.
<a name="line280"></a> * @param {number} startColIndex Left coordinate of the cells to merge.
<a name="line281"></a> * @param {number} endRowIndex Bottom coordinate of the cells to merge.
<a name="line282"></a> * @param {number} endColIndex Right coordinate of the cells to merge.
<a name="line283"></a> * @return {boolean} Whether or not the merge was possible. If the cells
<a name="line284"></a> *     in the supplied coordinates can&#39;t be merged this will return false.
<a name="line285"></a> */
<a name="line286"></a>goog.editor.Table.prototype.mergeCells = function(
<a name="line287"></a>    startRowIndex, startColIndex, endRowIndex, endColIndex) {
<a name="line288"></a>  // TODO(user): take a single goog.math.Rect parameter instead?
<a name="line289"></a>  var cells = [];
<a name="line290"></a>  var cell;
<a name="line291"></a>  if (startRowIndex == endRowIndex &amp;&amp; startColIndex == endColIndex) {
<a name="line292"></a>    this.logger_.warning(&quot;Can&#39;t merge single cell&quot;);
<a name="line293"></a>    return false;
<a name="line294"></a>  }
<a name="line295"></a>  // Gather cells and do sanity check.
<a name="line296"></a>  for (var i = startRowIndex; i &lt;= endRowIndex; i++) {
<a name="line297"></a>    for (var j = startColIndex; j &lt;= endColIndex; j++) {
<a name="line298"></a>      cell = this.rows[i].columns[j];
<a name="line299"></a>      if (cell.startRow &lt; startRowIndex ||
<a name="line300"></a>          cell.endRow &gt; endRowIndex ||
<a name="line301"></a>          cell.startCol &lt; startColIndex ||
<a name="line302"></a>          cell.endCol &gt; endColIndex) {
<a name="line303"></a>        this.logger_.warning(
<a name="line304"></a>            &quot;Can&#39;t merge cells: the cell in row &quot; + i + &#39;, column &#39; + j +
<a name="line305"></a>            &#39;extends outside the supplied rectangle.&#39;);
<a name="line306"></a>        return false;
<a name="line307"></a>      }
<a name="line308"></a>      // TODO(user): this is somewhat inefficient, as we will add
<a name="line309"></a>      // a reference for a cell for each position, even if it&#39;s a single
<a name="line310"></a>      // cell with row/colspan.
<a name="line311"></a>      cells.push(cell);
<a name="line312"></a>    }
<a name="line313"></a>  }
<a name="line314"></a>  var targetCell = cells[0];
<a name="line315"></a>  var targetTd = targetCell.element;
<a name="line316"></a>  var doc = this.dom_.getDocument();
<a name="line317"></a>
<a name="line318"></a>  // Merge cell contents and discard other cells.
<a name="line319"></a>  for (var i = 1; cell = cells[i]; i++) {
<a name="line320"></a>    var td = cell.element;
<a name="line321"></a>    if (!td.parentNode || td == targetTd) {
<a name="line322"></a>      // We&#39;ve already handled this cell at one of its previous positions.
<a name="line323"></a>      continue;
<a name="line324"></a>    }
<a name="line325"></a>    // Add a space if needed, to keep merged content from getting squished
<a name="line326"></a>    // together.
<a name="line327"></a>    if (targetTd.lastChild &amp;&amp;
<a name="line328"></a>        targetTd.lastChild.nodeType == goog.dom.NodeType.TEXT) {
<a name="line329"></a>      targetTd.appendChild(doc.createTextNode(&#39; &#39;));
<a name="line330"></a>    }
<a name="line331"></a>    var childNode;
<a name="line332"></a>    while ((childNode = td.firstChild)) {
<a name="line333"></a>      targetTd.appendChild(childNode);
<a name="line334"></a>    }
<a name="line335"></a>    td.parentNode.removeChild(td);
<a name="line336"></a>  }
<a name="line337"></a>  targetCell.setColSpan((endColIndex - startColIndex) + 1);
<a name="line338"></a>  targetCell.setRowSpan((endRowIndex - startRowIndex) + 1);
<a name="line339"></a>  if (endColIndex &gt; startColIndex) {
<a name="line340"></a>    // Clear width on target cell.
<a name="line341"></a>    // TODO(user): instead of clearing width, calculate width
<a name="line342"></a>    // based on width of input cells
<a name="line343"></a>    targetTd.removeAttribute(&#39;width&#39;);
<a name="line344"></a>    targetTd.style.width = null;
<a name="line345"></a>  }
<a name="line346"></a>  this.refresh();
<a name="line347"></a>
<a name="line348"></a>  return true;
<a name="line349"></a>};
<a name="line350"></a>
<a name="line351"></a>
<a name="line352"></a>/**
<a name="line353"></a> * Splits a cell with colspans or rowspans into multiple descrete cells.
<a name="line354"></a> * @param {number} rowIndex y coordinate of the cell to split.
<a name="line355"></a> * @param {number} colIndex x coordinate of the cell to split.
<a name="line356"></a> * @return {Array.&lt;Element&gt;} Array of new cell elements created by splitting
<a name="line357"></a> *     the cell.
<a name="line358"></a> */
<a name="line359"></a>// TODO(user): support splitting only horizontally or vertically,
<a name="line360"></a>// support splitting cells that aren&#39;t already row/colspanned.
<a name="line361"></a>goog.editor.Table.prototype.splitCell = function(rowIndex, colIndex) {
<a name="line362"></a>  var row = this.rows[rowIndex];
<a name="line363"></a>  var cell = row.columns[colIndex];
<a name="line364"></a>  var newTds = [];
<a name="line365"></a>  for (var i = 0; i &lt; cell.rowSpan; i++) {
<a name="line366"></a>    for (var j = 0; j &lt; cell.colSpan; j++) {
<a name="line367"></a>      if (i &gt; 0 || j &gt; 0) {
<a name="line368"></a>        var newTd = this.createEmptyTd();
<a name="line369"></a>        this.insertCellElement(newTd, rowIndex + i, colIndex + j);
<a name="line370"></a>        newTds.push(newTd);
<a name="line371"></a>      }
<a name="line372"></a>    }
<a name="line373"></a>  }
<a name="line374"></a>  cell.setColSpan(1);
<a name="line375"></a>  cell.setRowSpan(1);
<a name="line376"></a>  this.refresh();
<a name="line377"></a>  return newTds;
<a name="line378"></a>};
<a name="line379"></a>
<a name="line380"></a>
<a name="line381"></a>/**
<a name="line382"></a> * Inserts a cell element at the given position. The colIndex is the logical
<a name="line383"></a> * column index, not the position in the dom. This takes into consideration
<a name="line384"></a> * that cells in a given logical  row may actually be children of a previous
<a name="line385"></a> * DOM row that have used rowSpan to extend into the row.
<a name="line386"></a> * @param {Element} td The new cell element to insert.
<a name="line387"></a> * @param {number} rowIndex Row in which to insert the element.
<a name="line388"></a> * @param {number} colIndex Column in which to insert the element.
<a name="line389"></a> */
<a name="line390"></a>goog.editor.Table.prototype.insertCellElement = function(
<a name="line391"></a>    td, rowIndex, colIndex) {
<a name="line392"></a>  var row = this.rows[rowIndex];
<a name="line393"></a>  var nextSiblingElement = null;
<a name="line394"></a>  for (var i = colIndex, cell; cell = row.columns[i]; i += cell.colSpan) {
<a name="line395"></a>    if (cell.startRow == rowIndex) {
<a name="line396"></a>      nextSiblingElement = cell.element;
<a name="line397"></a>      break;
<a name="line398"></a>    }
<a name="line399"></a>  }
<a name="line400"></a>  row.element.insertBefore(td, nextSiblingElement);
<a name="line401"></a>};
<a name="line402"></a>
<a name="line403"></a>
<a name="line404"></a>/**
<a name="line405"></a> * Creates an empty TD element and fill it with some empty content so it will
<a name="line406"></a> * show up with borders even in IE pre-7 or if empty-cells is set to &#39;hide&#39;
<a name="line407"></a> * @return {Element} a new TD element.
<a name="line408"></a> */
<a name="line409"></a>goog.editor.Table.prototype.createEmptyTd = function() {
<a name="line410"></a>  // TODO(user): more cross-browser testing to determine best
<a name="line411"></a>  // and least annoying filler content.
<a name="line412"></a>  return this.dom_.createDom(goog.dom.TagName.TD, {}, goog.string.Unicode.NBSP);
<a name="line413"></a>};
<a name="line414"></a>
<a name="line415"></a>
<a name="line416"></a>
<a name="line417"></a>/**
<a name="line418"></a> * Class representing a logical table row: a tr element and any cells
<a name="line419"></a> * that appear in that row.
<a name="line420"></a> * @param {Element} trElement This rows&#39;s underlying TR element.
<a name="line421"></a> * @param {number} rowIndex This row&#39;s index in its parent table.
<a name="line422"></a> * @constructor
<a name="line423"></a> */
<a name="line424"></a>goog.editor.TableRow = function(trElement, rowIndex) {
<a name="line425"></a>  this.index = rowIndex;
<a name="line426"></a>  this.element = trElement;
<a name="line427"></a>  this.columns = [];
<a name="line428"></a>};
<a name="line429"></a>
<a name="line430"></a>
<a name="line431"></a>
<a name="line432"></a>/**
<a name="line433"></a> * Class representing a table cell, which may span across multiple
<a name="line434"></a> * rows and columns
<a name="line435"></a> * @param {Element} td This cell&#39;s underlying TD or TH element.
<a name="line436"></a> * @param {number} startRow Index of the row where this cell begins.
<a name="line437"></a> * @param {number} startCol Index of the column where this cell begins.
<a name="line438"></a> * @constructor
<a name="line439"></a> */
<a name="line440"></a>goog.editor.TableCell = function(td, startRow, startCol) {
<a name="line441"></a>  this.element = td;
<a name="line442"></a>  this.colSpan = parseInt(td.colSpan, 10) || 1;
<a name="line443"></a>  this.rowSpan = parseInt(td.rowSpan, 10) || 1;
<a name="line444"></a>  this.startRow = startRow;
<a name="line445"></a>  this.startCol = startCol;
<a name="line446"></a>  this.updateCoordinates_();
<a name="line447"></a>};
<a name="line448"></a>
<a name="line449"></a>
<a name="line450"></a>/**
<a name="line451"></a> * Calculates this cell&#39;s endRow/endCol coordinates based on rowSpan/colSpan
<a name="line452"></a> * @private
<a name="line453"></a> */
<a name="line454"></a>goog.editor.TableCell.prototype.updateCoordinates_ = function() {
<a name="line455"></a>  this.endCol = this.startCol + this.colSpan - 1;
<a name="line456"></a>  this.endRow = this.startRow + this.rowSpan - 1;
<a name="line457"></a>};
<a name="line458"></a>
<a name="line459"></a>
<a name="line460"></a>/**
<a name="line461"></a> * Set this cell&#39;s colSpan, updating both its colSpan property and the
<a name="line462"></a> * underlying element&#39;s colSpan attribute.
<a name="line463"></a> * @param {number} colSpan The new colSpan.
<a name="line464"></a> */
<a name="line465"></a>goog.editor.TableCell.prototype.setColSpan = function(colSpan) {
<a name="line466"></a>  if (colSpan != this.colSpan) {
<a name="line467"></a>    if (colSpan &gt; 1) {
<a name="line468"></a>      this.element.colSpan = colSpan;
<a name="line469"></a>    } else {
<a name="line470"></a>      this.element.colSpan = 1,
<a name="line471"></a>      this.element.removeAttribute(&#39;colSpan&#39;);
<a name="line472"></a>    }
<a name="line473"></a>    this.colSpan = colSpan;
<a name="line474"></a>    this.updateCoordinates_();
<a name="line475"></a>  }
<a name="line476"></a>};
<a name="line477"></a>
<a name="line478"></a>
<a name="line479"></a>/**
<a name="line480"></a> * Set this cell&#39;s rowSpan, updating both its rowSpan property and the
<a name="line481"></a> * underlying element&#39;s rowSpan attribute.
<a name="line482"></a> * @param {number} rowSpan The new rowSpan.
<a name="line483"></a> */
<a name="line484"></a>goog.editor.TableCell.prototype.setRowSpan = function(rowSpan) {
<a name="line485"></a>  if (rowSpan != this.rowSpan) {
<a name="line486"></a>    if (rowSpan &gt; 1) {
<a name="line487"></a>      this.element.rowSpan = rowSpan.toString();
<a name="line488"></a>    } else {
<a name="line489"></a>      this.element.rowSpan = &#39;1&#39;;
<a name="line490"></a>      this.element.removeAttribute(&#39;rowSpan&#39;);
<a name="line491"></a>    }
<a name="line492"></a>    this.rowSpan = rowSpan;
<a name="line493"></a>    this.updateCoordinates_();
<a name="line494"></a>  }
<a name="line495"></a>};
<a name="line496"></a>
<a name="line497"></a>
<a name="line498"></a>/**
<a name="line499"></a> * Optimum size of empty cells (in pixels), if possible.
<a name="line500"></a> * @type {number}
<a name="line501"></a> */
<a name="line502"></a>goog.editor.Table.OPTIMUM_EMPTY_CELL_WIDTH = 60;
<a name="line503"></a>
<a name="line504"></a>
<a name="line505"></a>/**
<a name="line506"></a> * Maximum width for new tables.
<a name="line507"></a> * @type {number}
<a name="line508"></a> */
<a name="line509"></a>goog.editor.Table.OPTIMUM_MAX_NEW_TABLE_WIDTH = 600;
<a name="line510"></a>
<a name="line511"></a>
<a name="line512"></a>/**
<a name="line513"></a> * Default color for table borders.
<a name="line514"></a> * @type {string}
<a name="line515"></a> */
<a name="line516"></a>goog.editor.Table.DEFAULT_BORDER_COLOR = &#39;#888&#39;;
<a name="line517"></a>
<a name="line518"></a>
<a name="line519"></a>/**
<a name="line520"></a> * Creates a new table element, populated with cells and formatted.
<a name="line521"></a> * @param {Document} doc Document in which to create the table element.
<a name="line522"></a> * @param {number} columns Number of columns in the table.
<a name="line523"></a> * @param {number} rows Number of rows in the table.
<a name="line524"></a> * @param {Object=} opt_tableStyle Object containing borderWidth and borderColor
<a name="line525"></a> *    properties, used to set the inital style of the table.
<a name="line526"></a> * @return {Element} a table element.
<a name="line527"></a> */
<a name="line528"></a>goog.editor.Table.createDomTable = function(
<a name="line529"></a>    doc, columns, rows, opt_tableStyle) {
<a name="line530"></a>  // TODO(user): define formatting properties as constants,
<a name="line531"></a>  // make separate formatTable() function
<a name="line532"></a>  var style = {
<a name="line533"></a>    borderWidth: &#39;1&#39;,
<a name="line534"></a>    borderColor: goog.editor.Table.DEFAULT_BORDER_COLOR
<a name="line535"></a>  };
<a name="line536"></a>  for (var prop in opt_tableStyle) {
<a name="line537"></a>    style[prop] = opt_tableStyle[prop];
<a name="line538"></a>  }
<a name="line539"></a>  var dom = new goog.dom.DomHelper(doc);
<a name="line540"></a>  var tableElement = dom.createTable(rows, columns, true);
<a name="line541"></a>
<a name="line542"></a>  var minimumCellWidth = 10;
<a name="line543"></a>  // Calculate a good cell width.
<a name="line544"></a>  var cellWidth = Math.max(
<a name="line545"></a>      minimumCellWidth,
<a name="line546"></a>      Math.min(goog.editor.Table.OPTIMUM_EMPTY_CELL_WIDTH,
<a name="line547"></a>               goog.editor.Table.OPTIMUM_MAX_NEW_TABLE_WIDTH / columns));
<a name="line548"></a>
<a name="line549"></a>  var tds = tableElement.getElementsByTagName(goog.dom.TagName.TD);
<a name="line550"></a>  for (var i = 0, td; td = tds[i]; i++) {
<a name="line551"></a>    td.style.width = cellWidth + &#39;px&#39;;
<a name="line552"></a>  }
<a name="line553"></a>
<a name="line554"></a>  // Set border somewhat redundantly to make sure they show
<a name="line555"></a>  // up correctly in all browsers.
<a name="line556"></a>  goog.style.setStyle(
<a name="line557"></a>      tableElement, {
<a name="line558"></a>        &#39;borderCollapse&#39;: &#39;collapse&#39;,
<a name="line559"></a>        &#39;borderColor&#39;: style.borderColor,
<a name="line560"></a>        &#39;borderWidth&#39;: style.borderWidth + &#39;px&#39;
<a name="line561"></a>      });
<a name="line562"></a>  tableElement.border = style.borderWidth;
<a name="line563"></a>  tableElement.setAttribute(&#39;bordercolor&#39;, style.borderColor);
<a name="line564"></a>  tableElement.setAttribute(&#39;cellspacing&#39;, &#39;0&#39;);
<a name="line565"></a>
<a name="line566"></a>  return tableElement;
<a name="line567"></a>};
</pre>


</body>
</html>
